/*
Copyright (C) 2010  Christoph Schnack, Berlin (Germany)

This file is part of Tribuit.

    Tribuit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tribuit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Tribuit.  If not, see <http://www.gnu.org/licenses/>.
*/
package PictureDescription;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import Settings.*;

/**
 * @author Christoph Schnack
 *
 */
public class DrawTags {
	Vector<PictureTagUnit> indexes;
	String indexNumber;
	Settings SET;
	boolean highlighted,marked,highlightVector;
	String hlIndexNumber;
	int selectedTagIndex,hlVectorNumber;
	double zoom;
	/**
	 * Constructor marking no element.
	 * 
	 * @param set Settings object
	 * @param g Graphics object
	 * @param in index number (will be increased by one by displaying))
	 * @param pipus pictureTagUnits
	 * @param hl highlight
	 * @param zoom zoom factor
	 */
	
	public DrawTags(Settings set,Graphics g,int in,Vector<PictureTagUnit> pipus,boolean hl,double z){
		this(set,g,in,pipus,hl,z,false,0,false,0);
	}
	
	/**
	 *Advanced constructor for marking elements.
	 * 
	 * @param set Settings object
	 * @param g Graphics object
	 * @param in index number (will be increased by one by displaying))
	 * @param pipus pictureTagUnits
	 * @param hl highlight
	 * @param zoom zoom factor
	 * @param hlVector highlightVector
	 * @param hlVctNumber hlVector number
	 * @param markd mark a tag
	 * @param selTag marked tag's number
	 */
	public DrawTags(Settings set,Graphics g,int in,Vector<PictureTagUnit> pipus,boolean hl,double z,boolean hlVector, int hlVctNumber,boolean markd,int selTag){
		SET=set;
		indexes=pipus;
		indexNumber=(in+1)+"";
		highlighted=hl;
		marked=markd;
		selectedTagIndex=selTag;
		zoom = z;
		highlightVector=hlVector;
		hlVectorNumber = hlVctNumber;
		if(!(indexes==null||g==null||in>99||indexes.size()==0)) paintIndexes(g);
	}
	
	public void paintIndexes(Graphics g){
		for(int i=0;i<indexes.size();i++){
			paintIndex(g,indexes.elementAt(i),i);
		}
	}
	
	public void paintIndex(Graphics g,PictureTagUnit pipu,int pipuIndex){
		Point pOriginal = pipu.getCenterPosition();
		Point p = new Point((int)Math.round(pOriginal.x*zoom),(int)Math.round(pOriginal.y*zoom));
		int radius = (int) Math.round(pipu.getRadius()*zoom),radius2=radius*2;
		if(pipu.hasTADEs()){
			Vector<TADE> pitas = pipu.getPictureTags();
			Graphics2D g2 = (Graphics2D)g;
			g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
			String type;
			for(int i=0;i<pitas.size();i++){
				TADE pt = pitas.elementAt(i);
				g.setColor(highlighted?pt.getFlashColor():pt.getColor());
				g2.setColor(highlighted?pt.getFlashColor():pt.getColor());
				if(highlightVector&&(hlVectorNumber==i)&&(pipuIndex==selectedTagIndex))g2.setColor(highlighted?pt.getColor():pt.getFlashColor()); 
				Point ptPoint=new Point((int)Math.round(pt.getPoint().x*zoom),(int)Math.round(pt.getPoint().y*zoom));
				type = pt.getType();
				g2.setStroke(new BasicStroke((float)zoom));
				if(type.startsWith("small")){
					g2.drawLine(p.x,p.y, p.x+ptPoint.x, p.y+ptPoint.y);
					int size=(int)Math.round(10*zoom);
					if(type.endsWith("Delimiter")){
						int[] dist = getDelimiterPoints(p,ptPoint,size);
						g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, p.x+dist[0],p.y-dist[1]);
						g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y,p.x+ptPoint.x+dist[2],p.y+ptPoint.y+dist[3]);
					}
					else{
						int[] dist = getArrowPoints(p,ptPoint,size);
						g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[0], dist[1]);
						g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[2], dist[3]);
					}
				}
				else{
					if(type.startsWith("medium")){
						g2.setStroke(new BasicStroke((float)zoom*3));
						g2.drawLine(p.x,p.y, p.x+ptPoint.x, p.y+ptPoint.y);
						int size=(int)Math.round(12*zoom);
						if(type.endsWith("Delimiter")){
							int[] dist = getDelimiterPoints(p,ptPoint,size);
							g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, p.x+dist[0],p.y-dist[1]);
							g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y,p.x+ptPoint.x+dist[2],p.y+ptPoint.y+dist[3]);
						}
						else{
							int[] dist = getArrowPoints(p,ptPoint,size);
							g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[0], dist[1]);
							g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[2], dist[3]);
						}
					}
					else{ 
						if(type.startsWith("big")){
							g2.setStroke(new BasicStroke((float)zoom*5));
							g2.drawLine(p.x,p.y, p.x+ptPoint.x, p.y+ptPoint.y);
							int size=(int)Math.round(14*zoom);
							if(type.endsWith("Delimiter")){
								int[] dist = getDelimiterPoints(p,ptPoint,size);
								g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, p.x+dist[0],p.y-dist[1]);
								g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y,p.x+ptPoint.x+dist[2],p.y+ptPoint.y+dist[3]);
							}
							else{
								int[] dist = getArrowPoints(p,ptPoint,size);
								g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[0], dist[1]);
								g2.drawLine(p.x+ptPoint.x, p.y+ptPoint.y, dist[2], dist[3]);
							}
						}
					}
				}
				g2.setStroke(new BasicStroke((float)zoom));
			}
		}
		g.setColor(highlighted?pipu.getBgHlColor():pipu.getBgColor());
		g.fillOval(p.x-radius, p.y-radius, radius2, radius2);
		g.setColor(pipu.getColor());
		g.drawOval(p.x-radius, p.y-radius, radius2, radius2);
		if(marked&&pipuIndex==selectedTagIndex){
			g.setColor(Color.red);
			g.drawRect(p.x-radius, p.y-radius, radius2, radius2);
			g.drawRect(p.x-(radius+1), p.y-(radius+1), radius2+2, radius2+2);
		}
		g.setColor(pipu.getColor());
		new DrawNumbers(g,pipu);
	}
	
	class DrawNumbers{
		int radius;
		
		public DrawNumbers(Graphics g,PictureTagUnit pipu){
			radius=(int)Math.round(pipu.getRadius()*zoom);
			Point centerP = new Point((int)Math.round(pipu.getCenterPosition().x*zoom),(int)Math.round(pipu.getCenterPosition().y*zoom));
			if(indexNumber.length()==2){
				int a = (int)Math.round(((Math.sqrt(((double)radius*radius)/2))/2)/2)+2;
				drawNumber(g,centerP.x-a,centerP.y, ""+indexNumber.charAt(0),true);
				drawNumber(g,centerP.x+a,centerP.y, ""+indexNumber.charAt(1),true);
			}
			else drawNumber(g,centerP.x,centerP.y,""+indexNumber,false);
		}
		
		/**
		 * Allots to each number the drawn segments 
		 * @param g
		 * @param x
		 * @param y
		 * @param number
		 */
		public void drawNumber(Graphics g,int x, int y,String number,boolean twoUnits){
			if(number.equals("0")) drawSegments(g,x,y,"123456",twoUnits);
			if(number.equals("1")) drawSegments(g,x,y,"823",twoUnits);
			if(number.equals("2")) drawSegments(g,x,y,"12754",twoUnits);
			if(number.equals("3")) drawSegments(g,x,y,"12347",twoUnits);
			if(number.equals("4")) drawSegments(g,x,y,"2367",twoUnits);
			if(number.equals("5")) drawSegments(g,x,y,"16734",twoUnits);
			if(number.equals("6")) drawSegments(g,x,y,"165473",twoUnits);
			if(number.equals("7")) drawSegments(g,x,y,"123",twoUnits);
			if(number.equals("8")) drawSegments(g,x,y,"1234567",twoUnits);
			if(number.equals("9")) drawSegments(g,x,y,"123467",twoUnits);
		}
		
		/**
		 * Draws the segments given of a digital number referring to x and y as it's center. The segments' numbers are counted from the top segment 1 clockwise and end with the middle segment 7.
		 * @param g
		 * @param x
		 * @param y
		 * @param arg
		 */
		public void drawSegments(Graphics g,int x, int y, String arg,boolean twoUnits){
			int a = (int) Math.round(((((Math.sqrt( ((double)radius*radius)/2 ))/2) )-1));
			if(twoUnits) a = (int)Math.round((((Math.sqrt( ((double)radius*radius)/2 )-1)/2)/2));
			int a2 = a*2;
			//1: top middle segment
			if(arg.contains("1")){
				g.drawLine(x-a, y-a2, x+a, y-a2);
			}
			//2: upper right segment
			if(arg.contains("2")){
				g.drawLine(x+a, y-a2, x+a, y);
			}
			//3: lower right segment
			if(arg.contains("3")){
				g.drawLine(x+a, y, x+a, y+a2);
			}
			//4: bottom segment
			if(arg.contains("4")){
				g.drawLine(x-a, y+a2, x+a, y+a2);
			}
			//5: lower left segment
			if(arg.contains("5")){
				g.drawLine(x-a, y+a2, x-a, y);
			}
			//6: upper left segment
			if(arg.contains("6")){
				g.drawLine(x-a, y, x-a, y-a2);
			}
			//7: middle segment
			if(arg.contains("7")){
				g.drawLine(x-a, y, x+a, y);
			}
			if(arg.contains("8")){
				g.drawLine(x, y-a, x+a, y-a2);
			}
		}
	}
	
	private int[] getDelimiterPoints(Point centerP,Point barg,int size){
		Point tagP = new Point(centerP.x+barg.x,centerP.y+barg.y);
		if(centerP.y==tagP.y)return new int[]{barg.x,size,0,size};
		if(centerP.x==tagP.x)return new int[]{size,-1*barg.y,-1*size,0};
		double y = centerP.y-tagP.y;
		double x = Math.abs(tagP.x-centerP.x);
		double c = Math.sqrt((Math.pow(x,2)+ Math.pow(y,2)));
		double f = Math.sqrt((c*c) + (size*size));
		double alpha = Math.toRadians( 90-(Math.toDegrees(Math.atan(size/c))+Math.toDegrees(Math.atan(y/x))) );
		int gy = (int)Math.round(Math.cos(alpha)*f);
		int hx = (int)Math.round(Math.sin(alpha)*f);
		if(tagP.x>centerP.x)return new int[]{hx,gy,tagP.x-(centerP.x+hx),gy-(centerP.y-tagP.y)};
		else return new int[]{-1*hx,gy,-1*(centerP.x-(tagP.x+hx)),gy-(centerP.y-tagP.y)};
	}
	
	private int[] getArrowPoints(Point centerP,Point tagParg,int size){
		Point tagP = new Point(centerP.x+tagParg.x,centerP.y+tagParg.y);
		double y = centerP.y-tagP.y;
		double x = tagP.x-centerP.x;
		double c = Math.abs(y);
		if(x==0 || y==0){
			if(y==0) c=Math.abs(x);
		}
		else c = Math.sqrt((Math.pow(x,2)+ Math.pow(y,2)));
		double slope = Math.abs(y)/Math.abs(x);
		double h = Math.sqrt( Math.pow(size,2) + Math.pow(c, 2) - (2*size*c*Math.cos(Math.toRadians(35))) );
		double hangle = Math.acos( (Math.pow(size, 2)-Math.pow(c,2) - Math.pow(h, 2)) / (-2*c*h) );
		double rangle = Math.atan(slope)- hangle;
		double rangle2 = Math.toRadians(90)-(rangle+(2*hangle));
		int yresult = (int)Math.round(Math.sin(rangle)*h);
		int xresult = (int)Math.round(Math.cos(rangle)*h);
		int yresult2 = (int)Math.round(Math.cos(rangle2)*h);
		int xresult2 = (int)Math.round(Math.sin(rangle2)*h);
		if(centerP.x<tagP.x) return (centerP.y<tagP.y)?new int[]{centerP.x+xresult,centerP.y+yresult,centerP.x+xresult2,centerP.y+yresult2}:new int[]{centerP.x+xresult,centerP.y-yresult,centerP.x+xresult2,centerP.y-yresult2};
		else return (centerP.y<tagP.y)?new int[]{centerP.x-xresult,centerP.y+yresult,centerP.x-xresult2,centerP.y+yresult2}:new int[]{centerP.x-xresult,centerP.y-yresult,centerP.x-xresult2,centerP.y-yresult2};
	}
}
